home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / Sample Code / DTS QT Utilities.May-95 / DTSQTUtilities.c < prev    next >
Encoding:
Text File  |  1995-04-30  |  49.1 KB  |  1,532 lines  |  [TEXT/MPCC]

  1. /*
  2.     File:        DTSUtilities.c
  3.  
  4.     Contains:    QuickTime functions.
  5.  
  6.     Written by:    DTS
  7.  
  8.     Copyright:    © 1994-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.        <1>         12/17/94    khs        first file
  13.        
  14. */
  15.  
  16.  
  17. // INCLUDES
  18. #include "DTSQTUtilities.h"
  19.  
  20.  
  21. // MOVIE TOOLBOX FUNCTIONS
  22.  
  23. /*______________________________________________________________________
  24.     QTUIsQuickTimeInstalled - Test if QuickTime is installed.
  25.  
  26. pascal Boolean    QTUIsQuickTimeInstalled(void) 
  27.  
  28. DESCRIPTION
  29.     InitQuickTime will test if QuickTime is present. We are not interested in the QuickTime
  30.     version.
  31.  
  32. ISSUES
  33.     You could combine this function with the QTUGetQTVersion so you could also fetch the
  34.     version level of QT at the same time.
  35. */
  36.  
  37. pascal Boolean QTUIsQuickTimeInstalled(void) 
  38. {
  39.     OSErr     anErr = noErr;
  40.     long         qtVersion;
  41.  
  42.     anErr = Gestalt(gestaltQuickTime, &qtVersion); DebugAssert(anErr == noErr);
  43.     if (anErr != noErr)
  44.         return false;        // no QT present
  45.     else
  46.         return true;
  47. }
  48.  
  49.  
  50. /*______________________________________________________________________
  51.     QTUIsQuickTimeCFMInstalled - Test if the QuickTime CFM libraries are installed and in the 
  52.     right place.
  53.  
  54. pascal Boolean    QTUIsQuickTimeCFMInstalled(void) 
  55.  
  56. DESCRIPTION
  57.     QTUIsQuickTimeCFMInstalled will test if the CFM QuickTime libraries are present (QuickTime 
  58.     PowerPlug, for instance), and if the libraries are still present (this because the libraries are 
  59.     registered once when Gestalt finds then during runtime, and the end user might delete these, 
  60.     or move them to another location later)(.
  61. */
  62.  
  63. #ifdef powerc
  64. pascal Boolean QTUIsQuickTimeCFMInstalled(void) 
  65. {
  66.     OSErr     anErr = noErr;
  67.     long         qtFeatures = 0L; 
  68.  
  69. // Test if the library is registered.
  70.     anErr = Gestalt(gestaltQuickTimeFeatures, &qtFeatures); DebugAssert(anErr == noErr);
  71.     
  72.     if (!(  (anErr == noErr)  &&  (qtFeatures & (1 << gestaltPPCQuickTimeLibPresent))  )) // not true
  73.           return false;
  74.           
  75. // Test if a function is available (the library is not moved from the Extension folder),  this is the 
  76. // trick to be used concerning testing if a function is available via CFM.
  77.  
  78.     if   ( ! CompressImage )
  79.         return false;     
  80.     else 
  81.         return true;
  82. }
  83. #endif // powerc
  84.  
  85.  
  86. /*______________________________________________________________________
  87.     QTUGetQTVersion - Return the current QuickTime version number.
  88.  
  89. pascal long QTUGetQTVersion()
  90.  
  91. DESCRIPTION
  92.     QTUGetQTVersion is a simple function that will return the current QuickTime version number,
  93.     and if QuickTime is not installed it will return 0L.  The high order word defines the version number, 
  94.     for instance 0x0161 defines version 1.6.1.
  95.     
  96.     You could also directly assign a boolean value stating if a certain version is true by using this
  97.     kind of an expression:
  98.     
  99.     Boolean gHasQT2.0 = (( QTUGetQTVersion() >>  16) & 0xFFFF) >= 0x200;
  100.     
  101. EXAMPLE
  102.     if( (QTUGetQTVersion() >> 16) < 0x150 ) return; // need to work with QT 1.5 or higher.
  103. */
  104.  
  105. pascal long QTUGetQTVersion()
  106. {
  107.     long version = 0L;
  108.     
  109.     if(Gestalt(gestaltQuickTime, &version) == noErr)
  110.         return version;
  111.     else
  112.         return 0L;
  113. }
  114.  
  115.  
  116. /*______________________________________________________________________
  117.     QTUAreQuickTimeMusicInstrumentsPresent - Test if the Musical Instruments Extension is 
  118.     installed.
  119.  
  120. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  121.  
  122. DESCRIPTION
  123.     QTUAreQuickTimeMusicInstrumentsPresent tests if the QuickTime Musical Instruments
  124.     extension (actually a component) is registered. If this is not the case, then most likely
  125.     the extension was never placed into the extension folder, and the end user should be
  126.     informed about this.
  127. */
  128.  
  129. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  130. {
  131.     ComponentDescription aCD;
  132.     
  133.     aCD.componentType = 'inst';
  134.     aCD.componentSubType = 'ss  ';
  135.     aCD.componentManufacturer = 'appl';
  136.     
  137.     if(FindNextComponent((Component)0, &aCD) != NULL)
  138.         return true;
  139.     else
  140.         return false;
  141. }
  142.  
  143.  
  144. /*______________________________________________________________________
  145.      QTUPrerollMovie - Preroll the movie before you start the movie.
  146.  
  147. pascal OSErr QTUPrerollMovie(Movie theMovie)
  148.  
  149. theMovie                the destination movie for this operation
  150.  
  151. DESCRIPTION
  152.     QTUPrerollMovie will get the movie time,  duration and preferred rate, and Preroll the movie 
  153.     based on this information. Note that StartMovie already does a PrerollMovie so in that case this 
  154.     is not needed, this is also true of the standard controller that handles the start of movie
  155.     when the keyboard or mouse is used.
  156. */
  157.  
  158. pascal OSErr QTUPrerollMovie(Movie theMovie) 
  159. {
  160.     OSErr                anErr = noErr;
  161.     TimeValue         aTimeValue;
  162.     TimeValue         aMovieDur;
  163.     Fixed                 aPreferredRate;
  164.  
  165.     aTimeValue          = GetMovieTime(theMovie, NULL);
  166.     aMovieDur         = GetMovieDuration(theMovie);
  167.     aPreferredRate  = GetMoviePreferredRate(theMovie);
  168.  
  169.     anErr = PrerollMovie(theMovie, aTimeValue, aPreferredRate); DebugAssert(anErr == noErr);
  170.     
  171.     return anErr;
  172. }
  173.  
  174.  
  175. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock);
  176.  
  177.  
  178. /*______________________________________________________________________
  179.     QTUGetMovie - Get a Movie from a specific file.
  180.  
  181. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  182.  
  183. theFSSpec                the specific FSSpec used, if NULL the system will use a standard dialog
  184.                             box for the end user to select a file
  185. theRefNum            this is the specific file ref num we want to use later
  186. theResID                this is the specific resource ID we want to use later
  187.  
  188. DESCRIPTION
  189.     QTUGetMovie will get a movie resource out from a specified file, if the FSSpec is not provided
  190.     then the function will use a StandardGetFilePreview to select the movie.
  191. */
  192.  
  193. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  194. {
  195.     OSErr                    anErr = noErr;
  196.     SFTypeList            aTypeList = {MovieFileType, 0, 0, 0};
  197.     StandardFileReply    aReply;
  198.     Movie                    aMovie = NULL;
  199.     
  200. // If we are provided with an FSSpec then use it, otherwise do a standardgetfile dialog box and 
  201. // ask the end user to get it.
  202.     if(theFSSpec == NULL || theFSSpec->vRefNum == 0)
  203.     {    
  204.         StandardGetFilePreview( NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply);
  205.         if(! aReply.sfGood)
  206.             return NULL;
  207.         
  208.         *theFSSpec = aReply.sfFile;
  209.     }
  210.  
  211.     // We should have now a usable FSSpec, just double check this once again before continuing.
  212.     DebugAssert(theFSSpec != NULL); if(theFSSpec == NULL) return NULL;
  213.     
  214.     anErr = OpenMovieFile(theFSSpec, theRefNum, fsRdPerm); DebugAssert(anErr == noErr);
  215.     // Note we define fsRdPerm, you could use another flag if needed.
  216.  
  217.     if(anErr == noErr)
  218.     {
  219.         Str255    aMovieName;
  220.         Boolean    wasChanged;
  221.         
  222.         *theResID = 0;                    // want first movie
  223.         
  224.         anErr = NewMovieFromFile(&aMovie, *theRefNum, theResID,
  225.                                                     aMovieName, newMovieActive, &wasChanged);
  226.         DebugAssert(anErr == noErr);
  227.  
  228.         CloseMovieFile(*theRefNum);
  229.     }
  230.     
  231.     if(anErr != noErr)
  232.         return NULL;
  233.     else
  234.         return aMovie;
  235. }
  236.  
  237.  
  238. /*______________________________________________________________________
  239.     QTUFileFilter - Skeleton file filter to be used with various MovieToolbox standard dialog utilities.
  240.  
  241. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock)
  242.  
  243. theParamBlock        specifies a particular ParmBlockPtr
  244.  
  245. DESCRIPTION
  246.     QTUFileFilter is a skeleton file filter to be used with various MovieToolbox standard dialog utilities
  247.     The function will return a boolean false if it encounters any errors from the Movie toolbox.
  248. */
  249.  
  250. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock)
  251. {
  252.     return false;
  253. }
  254.  
  255.  
  256. /*______________________________________________________________________
  257.       QTUSaveMovie - Save and flatten a movie resource into a  file.
  258.  
  259. pascal OSErr QTUSaveMovie(Movie theMovie)
  260.  
  261. theMovie            defines the movie to be saved into a file
  262.  
  263. DESCRIPTION
  264.     QTUSaveMovie will provide a user dialog asking for a file name, and will then save the movie
  265.     into this file. Note that this function will also automatically flatten the movie so that  it's 
  266.     self-contained, and also make it cross-platform (by adding any possible resource forks to
  267.     the end of the data fork. The default name of the movie is also NEWMOVIE.MOV, this reflects
  268.     the way movie file names should be named for cross-platform support (Windows). The default
  269.     creator type is also 'TVOD' so that MoviePlayer will be the default application that opens the
  270.     movie file. If there's an existing movie file with the same name, it will be deleted.
  271. */
  272.  
  273.  
  274. pascal OSErr QTUSaveMovie(Movie theMovie)
  275. {
  276.     OSErr                     anErr = noErr;
  277.     StandardFileReply    anSFReply;
  278.     
  279.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  280.     
  281.     StandardPutFile("\pSave Movie as:" , "\pNEWMOVIE.MOV", &anSFReply); 
  282.     if(anSFReply.sfGood)
  283.     {
  284.  
  285.         FlattenMovieData(theMovie, flattenAddMovieToDataFork, &anSFReply.sfFile, 
  286.                                         'TVOD', smSystemScript, createMovieFileDeleteCurFile );
  287.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  288.     }
  289.         return anErr;
  290. }
  291.  
  292.  
  293. /*______________________________________________________________________
  294.     QTUFlattenMovieFile - Flatten a movie into a specified file.
  295.  
  296. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  297.  
  298. theMovie                defines the movie to be flattened
  299. theFile                    defines the target file
  300.  
  301. DESCRIPTION
  302.     FlattenMovie file will take an existing movie, flatten it into a temp file, and then move the
  303.     contents of the temp file into the specified FSSpec. This because there are cases where we 
  304.     can't flatten a movie in place. We will use TickCount as a temp file name.    
  305.     
  306.     Note that we need to dispose the movie inside this function? Why? Well, the file is open as
  307.     long as there's a pointer to it from the movie resource. And we need to delete the original 
  308.     movie file as part of the operation of swapping the files. 
  309. */
  310.  
  311. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  312. {
  313.     OSErr         anErr = noErr;
  314.     FSSpec         tempFile;
  315.     Str255     tempFileName;
  316.     
  317.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  318.     
  319.     // Create the needed temp file.
  320.     NumToString(TickCount(), tempFileName);
  321.         anErr = FSMakeFSSpec(theFile->vRefNum, theFile->parID, tempFileName, &tempFile);
  322.     if(anErr != fnfErr) return anErr;
  323.     
  324.     // Flatten the movie.
  325.     FlattenMovie(theMovie, flattenAddMovieToDataFork, &tempFile, 'TVOD', smSystemScript, 
  326.                             createMovieFileDeleteCurFile, 0, NULL);
  327.     anErr = GetMoviesError();
  328.     if(anErr != noErr)
  329.     {
  330.         FSpDelete(&tempFile);        // remove the temp file
  331.         return anErr;
  332.     }
  333.     
  334.     DisposeMovie(theMovie);
  335.     anErr = FSpDelete(theFile);  ReturnIfError(anErr);
  336.     anErr = FSpRename(&tempFile, theFile->name); ReturnIfError(anErr);
  337.     
  338.     return anErr;
  339. }
  340.  
  341.  
  342. // TRACKS AND MEDIA
  343.  
  344. /*______________________________________________________________________
  345.     QTUMediaTypeInTrack - Check if a particular media type is present in the movie.
  346.  
  347. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  348.  
  349. theMovie                    movie to be tested about the media type
  350. theMediaType            media type we want to test about
  351.  
  352. DESCRIPTION
  353.     QTUMediaTypeInTrack could be used to scan if a possible media type is present in the movie 
  354.     (video,sound, other media types).
  355. */
  356.  
  357. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  358. {
  359.     Track         aTrack = NULL;
  360.     long            aTrackCount = 0;
  361.     long            index;
  362.     OSType        aMediaType;
  363.     Boolean        haveMediaType = false;
  364.     
  365.     aTrackCount = GetMovieTrackCount(theMovie);
  366.     if(aTrackCount == 0)
  367.         return false;                // no tracks in movie
  368.     
  369.     for(index = 1; index <= aTrackCount; index++)
  370.     {
  371.         aTrack = GetMovieIndTrack(theMovie, index);
  372.         GetMediaHandlerDescription( GetTrackMedia(aTrack), &aMediaType, NULL, NULL);
  373.         
  374.         haveMediaType = ( aMediaType == theMediaType);
  375.         if(haveMediaType == true)
  376.             return true;
  377.     }
  378.     return false;            // didn't find the media type track in the movie
  379. }
  380.  
  381.  
  382. /*______________________________________________________________________
  383.     QTUGetTrackRect - Get the Rect of a specified  track.
  384.  
  385. pascal Rect QTUGetTrackRect(Track theTrack)
  386.  
  387. theTrack                track we are interested in concerning the rect information
  388.  
  389. DESCRIPTION
  390.     QTUMediaTypeInTrack will take a (visual) track and return the track's Rect boundaries that 
  391.     could be used later for various calculations of the visual track geometries. Note that
  392.     this Rect is meaningful with video tracks (and any other tracks that have geometrical
  393.     dimensions, otherwise this function will return a rect with zero values.
  394.  
  395. ISSUES
  396.     Should we test if the track is a visual one and if so bail out? If so we need to send down a 
  397.     pointer to a Rect and return OSErrs.
  398. */
  399.  
  400. pascal OSErr QTUGetTrackRect(Track theTrack, Rect *theRect)
  401. {
  402.     OSErr    anErr = noErr;
  403.     Fixed    aTrackHeight;
  404.     Fixed    aTrackWidth;
  405.  
  406.     theRect->top = 0; theRect->left = 0; theRect->bottom = 0; theRect->right = 0;
  407.     
  408.     DebugAssert(theTrack != NULL);
  409.     if(theTrack == NULL)
  410.         return invalidTrack;
  411.         
  412.     GetTrackDimensions(theTrack, &aTrackHeight, &aTrackWidth);
  413.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  414.     if(anErr != noErr)
  415.         return anErr;
  416.     
  417.     theRect->right = Fix2Long(aTrackWidth);
  418.     theRect->bottom = Fix2Long(aTrackHeight);
  419.     
  420.     return anErr;
  421. }
  422.  
  423.  
  424. /*______________________________________________________________________
  425.     QTUGetVideoMediaPixelDepth - Return the pixel depth of the video media (sample).
  426.  
  427. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  428.  
  429. theMedia            visual media we want to test concerning pixel depths
  430. index                   index into the media sample we are interested in
  431.  
  432. DESCRIPTION
  433.     QTUGetVideoMediaPixelDepth will take a specified video media and an index into the media 
  434.     samples, and look up the pixel depth for the video sample.
  435. */
  436.  
  437. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  438. {
  439.     OSErr                                 anErr = noErr;
  440.     short                                 aPixelDepth;
  441.     SampleDescriptionHandle    anImageDesc = NULL;
  442.     OSType                                 mediaType;
  443.     
  444.     DebugAssert(theMedia != NULL);
  445.     DebugAssert(index > 0);
  446.     
  447.     // Test if we are indeed dealing with video media.
  448.     GetMediaHandlerDescription(theMedia, &mediaType, NULL, NULL);
  449.     if(mediaType != VideoMediaType)
  450.         return 0;
  451.         
  452.     anImageDesc = (SampleDescriptionHandle)NewHandle(sizeof(Handle)); DebugAssert(anImageDesc != NULL);
  453.     if(anImageDesc == NULL)
  454.         return 0;
  455.     
  456.     GetMediaSampleDescription(theMedia, index, anImageDesc);
  457.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  458.     
  459.     aPixelDepth = (* (ImageDescriptionHandle)anImageDesc)->depth;
  460.     
  461.     DisposeHandle((Handle)anImageDesc);
  462.     
  463.     return aPixelDepth;
  464. }
  465.  
  466.  
  467. /*______________________________________________________________________
  468.     QTUCountMediaSamples - Count the amount of known media samples in a movie.
  469.  
  470. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  471.  
  472. theMovie                    the movie with the track(tracks).    
  473. theMediaType            the type of media we are interested in (video, sound and so on)
  474.  
  475. DESCRIPTION
  476.     QTUCountMediaSamples will take a specified movie and a media type, and calculate the amount 
  477.     of samples of this particular type. It could be used to find the total amount of video frames in a 
  478.     movie, or sound samples and so on.
  479.  
  480.     Note that if the movie is long, it will take a long time to go through all the samples, especially 
  481.     in the case of sound samples.
  482.  
  483. EXAMPLE:
  484.     nFrames = QTUCountMediaSamples(aSourceMovie, VideoMediaType); 
  485.  
  486. ISSUES
  487.     This function could be modified to count other types of samples by changing the flags definitions 
  488.     (nextTimeSyncSample for key frames and so on).
  489. */
  490.  
  491. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  492. {
  493.     long                 numFrames = 0;
  494.     short             flags = nextTimeMediaSample + nextTimeEdgeOK;
  495.     TimeValue        aDuration = 0;
  496.     TimeValue     theTime = 0;
  497.     
  498.     GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  499.     if(theTime == -1) return numFrames;
  500.  
  501.     flags = nextTimeMediaSample; // Don't include the  nudge after the first interesting time.
  502.     
  503.     while(theTime != -1)  // When the returned time equals -1, then there were no more interesting times.
  504.     {
  505.         numFrames++;
  506.         GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  507.     }
  508.     
  509.     return numFrames;
  510. }
  511.  
  512.  
  513. /*______________________________________________________________________
  514.     QTUGetDurationOfFirstMovieSample - Return the time value of the first sample of a certain 
  515.     media type.
  516.  
  517. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  518.  
  519. theMovie                        the movie with the media track
  520. theMediaType                specified media type (VideoMediaType, SoundMediaType and so on)
  521.  
  522. DESCRIPTION
  523.     QTUGetDurationOfFirstMovieSample returns the duration of the first sample of a certain media 
  524.     in the movie. If there is no such sample, the duration is 0.
  525.  
  526.     This function could be used in known cases where all the samples are assumed to be of the same 
  527.     duration. For instance in such cases the frame count could be calculated as:
  528.  
  529.     framecount =
  530.              GetMovieDuration(theMovie)/QTUGetDurationofFirstMovieSample(theMovie, VideoMediaType);
  531.  
  532. */
  533.  
  534. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  535. {
  536.     OSErr             anErr = noErr;
  537.     TimeValue        interestingDuration = 0;
  538.     short            timeFlags = nextTimeMediaSample+nextTimeEdgeOK;
  539.  
  540.     GetMovieNextInterestingTime(theMovie, timeFlags, (TimeValue)1, &theMediaType, 0, 
  541.                                                     fixed1, NULL, &interestingDuration);
  542.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  543.  
  544.     return interestingDuration;
  545. }
  546.  
  547.  
  548. /*______________________________________________________________________
  549.     QTUCountMaxSoundRate - Calculate the max sound data rate of a possible sound track
  550.    in the movie.
  551.  
  552. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  553.  
  554. theMovie                        the movie with the sound track(tracks).    
  555. theMaxSoundRate            the final returned rate value.
  556.  
  557. DESCRIPTION
  558.     QTUCountMaxSoundRate (taken from the ConvertToMovieJr file) is a simple function that tries
  559.     to figure out the maximum sound track rate. This is done by looking at all of the sound tracks
  560.     in the source movie, and using the one with the highest sample rate (11khz, 22khz and so on),
  561.  
  562.     This number could then be used for calculating the maximum data rate by extracting the sound rate and 
  563.     this way we get a loose estimation how much is left for the video data rate.
  564.     
  565.     This is just an approximation, and a better function should take into account non-overlapping
  566.     sound tracks, stereo sound data rates, compressed sound tracks and so on.
  567. */
  568.  
  569. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  570. {
  571.     OSErr    anErr = noErr;
  572.     short     index, trackCount;
  573.     
  574.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  575.     *theMaxSoundRate = 0; // just for security we place this value in here
  576.     
  577.     trackCount = GetMovieTrackCount(theMovie);
  578.     
  579.     for(index = 1; index <= trackCount; index++)
  580.     {
  581.         OSType     aTrackType;
  582.         Track        aTrack = NULL;
  583.         Media        aMedia = NULL;
  584.         
  585.         aTrack = GetMovieIndTrack(theMovie, index);  DebugAssert(aTrack != NULL);
  586.         aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL);
  587.         anErr = GetMoviesError();  DebugAssert(anErr == noErr);
  588.         if(anErr != noErr) return anErr;
  589.         
  590.         GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
  591.         if(aTrackType == SoundMediaType)
  592.         {
  593.             long aRate;
  594.             SampleDescriptionHandle aDesc = NULL;
  595.             
  596.             aDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); DebugAssert(aDesc != NULL);
  597.             GetMediaSampleDescription(aMedia, 1, aDesc);
  598.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  599.             if(anErr != noErr)
  600.             {
  601.                 DisposeHandle((Handle)aDesc);
  602.                 continue;
  603.             }
  604.             
  605.             aRate = (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16;
  606.             if(aRate > *theMaxSoundRate)
  607.                 *theMaxSoundRate = aRate;
  608.         }
  609.     }
  610.     return anErr;
  611. }
  612.  
  613.  
  614.  
  615. /*______________________________________________________________________
  616.     QTUGetMovieFrameCount - Return the amount of frames in the movie based on frame rate estimate.
  617.  
  618. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  619.  
  620. theMovie                    the movie we want to calculate the frame count for.            
  621. theFrameRate            the expected frame rate of the movie
  622.  
  623. DESCRIPTION
  624.     QTUGetMovieFrameCount is a simple operation that takes into account the duration of the movie,
  625.     the time scale and a suggested frame rate, and based on this will calculate the 
  626.     amount of frames needed in the movie. We assume that the frame rate will be uniform in the movie.
  627. */
  628.  
  629. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  630. {
  631.     long         frameCount, duration, timescale;
  632.     float     exactFrames;
  633.     
  634.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  635.  
  636.     duration         = GetMovieDuration(theMovie);
  637.     timescale         = GetMovieTimeScale(theMovie);
  638.     exactFrames    = (float)duration * theFrameRate;
  639.     
  640.     frameCount    = exactFrames / timescale / 65536;
  641.     
  642.     if(frameCount == 0)
  643.         frameCount = 1;            // we got to have at least one frame
  644.     
  645.     return frameCount;
  646. }
  647.  
  648.  
  649. /*______________________________________________________________________
  650.     QTUCopySoundTracks - Copy any sound track from the source movie to the destination movie.
  651.  
  652. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  653.  
  654. aSourceMovie                 movie from which to copy the sound tracks            
  655. aDestinationMovie             movie to which we will copy the sound tracks.    
  656.  
  657. DESCRIPTION
  658.     QTUCopySoundTracks will take any sound tracks from the source movie, and copy these over to the
  659.     destination movie. The destination movie might have no sound track, or then these tracks are 
  660.     added to the existing sound tracks.
  661. */
  662.  
  663. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  664. {
  665.     OSErr     anErr = noErr;
  666.     long        trackCount, index;
  667.     
  668.     DebugAssert(theSrcMovie != NULL); if(theSrcMovie == NULL) return invalidMovie;
  669.     DebugAssert(theDestMovie != NULL); if(theDestMovie == NULL) return invalidMovie;
  670.  
  671.     trackCount = GetMovieTrackCount(theSrcMovie);
  672.     
  673.     // Loop through each track, look for sound tracks.
  674.     for(index = 1; index <= trackCount; index++)
  675.     {
  676.         OSType aTrackType;
  677.         Track    aSrcTrack, aDestTrack;
  678.         Media    aSrcMedia, aDestMedia;
  679.         
  680.         aSrcTrack = GetMovieIndTrack(theSrcMovie, index);            // get next track and media
  681.         aSrcMedia = GetTrackMedia(aSrcTrack);
  682.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  683.         if(anErr != noErr) return anErr;
  684.         
  685.         // try to find sound tracks/media
  686.         GetMediaHandlerDescription(aSrcMedia, &aTrackType, 0, 0);
  687.         if(aTrackType == SoundMediaType)
  688.         {
  689.             // Create the track for the sound media.
  690.             aDestTrack = NewMovieTrack(theDestMovie, 0, 0, GetTrackVolume(aSrcTrack));
  691.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  692.             if(anErr != noErr) return anErr;
  693.             
  694.             // Create a media for the sound track and prepare this media for editing.
  695.             aDestMedia = NewTrackMedia(aDestTrack, SoundMediaType, GetMediaTimeScale(aSrcMedia), 0, 0);
  696.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  697.             if(anErr != noErr) return anErr;
  698.             
  699.             anErr = BeginMediaEdits(aDestMedia); DebugAssert(anErr == noErr);
  700.             if(anErr != noErr) return anErr;
  701.             
  702.             // Insert the new track into the destination movie starting at time zero and
  703.             // lasting for the entire duration of the movie.
  704.             InsertTrackSegment(aSrcTrack, aDestTrack, 0 , GetTrackDuration(aSrcTrack), 0);
  705.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  706.             if(anErr != noErr) return anErr;
  707.             
  708.             // We've done editing the media
  709.             EndMediaEdits(aDestMedia);
  710.         }
  711.     }
  712.     return anErr;
  713. }
  714.  
  715.  
  716.  
  717. /*______________________________________________________________________
  718.     QTUPrintMoviePoster - Print the existing movie poster.
  719.  
  720. pascal Boolean QTUPrintMoviePoster(Movie theMovie, short x, short y)
  721.  
  722. theMovie                    movie that has the poster        
  723. x,y                            starting point coordinates where to place the poster on paper
  724.  
  725. DESCRIPTION
  726.     QTUPrintMoviePoster is a simple function showing how to print movie posters. 
  727.  
  728. ISSUES
  729.     Note that in a real application we should put the PrStlDialog code into the Print Setup… menu
  730.     function. The reason it's inside this function is that we use this code for quick testing of 
  731.     printing.
  732.  
  733.     Also, if we want to print the current movie frame, you could get the pict of the current one
  734.     by this code:
  735.         thePICT = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L));
  736.  
  737. */
  738.  
  739. pascal Boolean QTUPrintMoviePoster(Movie theMovie, short x, short y)
  740. {
  741.     PicHandle     aPictHandle;
  742.     THPrint        aTHPrint;
  743.     GrafPtr         aSavedPort;
  744.     TPPrPort    aPrintPort;
  745.     Boolean     aResult;
  746.     Rect            aPictRect;
  747.     
  748.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  749.     if(theMovie == NULL) return false;
  750.     
  751.     GetPort(&aSavedPort);
  752.     
  753.     aPictHandle = GetMoviePosterPict(theMovie); 
  754.     if(aPictHandle == NULL) goto Closure;                  // no movie poster PICT
  755.     
  756.     aTHPrint = (THPrint) NewHandleClear(sizeof(TPrint)); DebugAssert(aTHPrint != NULL);
  757.     if(aTHPrint == NULL) goto Closure;
  758.  
  759.     PrOpen();
  760.     PrintDefault(aTHPrint);
  761.  
  762. // Move this to Print Setup…if you want to make this look really cool.    
  763.     aResult = PrStlDialog(aTHPrint); DebugAssert(aResult == true);
  764.     if(!aResult) goto Closure;
  765.     
  766.     aResult = PrJobDialog(aTHPrint); DebugAssert(aResult == true);
  767.     if(!aResult) goto Closure;
  768.     
  769.     aPrintPort = PrOpenDoc(aTHPrint, NULL, NULL); DebugAssert(aPrintPort != NULL);
  770.     PrOpenPage(aPrintPort, NULL);
  771.     
  772. // Print at x,y position
  773.     aPictRect =  (*aPictHandle)->picFrame;
  774.     OffsetRect(&aPictRect, x - aPictRect.left,  y  - aPictRect.top);
  775.     
  776.     DrawPicture(aPictHandle, &aPictRect);
  777.  
  778. // If you want to do additional drawing, do it here.
  779.     
  780.     PrClosePage(aPrintPort);
  781.     PrCloseDoc(aPrintPort);
  782.     
  783.     if(( *aTHPrint)->prJob.bJDocLoop == bSpoolLoop)
  784.         PrPicFile(aTHPrint, NULL, NULL, NULL, NULL);
  785.     
  786.     PrClose();
  787.  
  788. // Normal behavior, we exit here.    
  789.     return true;
  790.  
  791. // Our failure handling process.
  792. Closure:
  793.     SetPort(aSavedPort);
  794.     
  795.     if(aPictHandle) KillPicture(aPictHandle);
  796.     if(aTHPrint) DisposeHandle((Handle)aTHPrint);
  797.     return false;
  798. }
  799.  
  800. /*______________________________________________________________________
  801.     QTUCalculateMovieMemorySize - Calculate how much memory a movie takes in the app heap.
  802.  
  803. pascal long QTUCalculateMovieMemorySize(Movie theMovie)
  804.  
  805. theMovie                        movie we want to know the size of in the current application heap.
  806.  
  807. DESCRIPTION
  808.     QTUCalculateMovieMemorySize will return the amount of bytes it is allocating as a handle
  809.     in the current application heap, if there's not enough space for a temp handle, or if anything
  810.     else fails, the function will return 0L.
  811.  
  812. ISSUES
  813.     Note that possible movie controllers associated with the movie and other constructs will eat up
  814.     memory. What you could do is to do a MacsBug HT before the movie or movies are opened, 
  815.     check the amount of free space, and HT after the movies are opened, figure out the movie sizes 
  816.     using the function below, and calculate the delta from these values.
  817. */
  818.  
  819. pascal long QTUCalculateMovieMemorySize(Movie theMovie)
  820. {
  821.     OSErr     anErr = noErr;
  822.     long         movieSize = 0L;
  823.     Handle    tempHandle = NULL;
  824.  
  825.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  826.  
  827.     tempHandle = NewHandle(sizeof(Movie)); DebugAssert(tempHandle != NULL);
  828.     if(tempHandle != NULL)
  829.     {
  830.         anErr =  PutMovieIntoHandle(theMovie, tempHandle); DebugAssert(anErr == noErr);
  831.  
  832.         if(anErr == noErr)    
  833.             movieSize = GetHandleSize(tempHandle);
  834.     }
  835.  
  836.     if(tempHandle != NULL) DisposeHandle(tempHandle);
  837.  
  838.     return movieSize;
  839. }
  840.  
  841.  
  842. /*______________________________________________________________________
  843.     QTULoadWholeMovieToRAM - Load the entire active segment (movie) into RAM
  844.  
  845. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  846.  
  847. theMovie                        movie we want to know the size of in the current application heap.
  848.  
  849. DESCRIPTION
  850.     QTULoadWholeMovieToRAM is an example of how to load movie information into RAM. In
  851.     this case we will load the entire movie, or in other words all the active segments.
  852.  
  853. ISSUES
  854.     The most likely error returned from this function is due to lack of memory.  You could 
  855.     also fine tune this function by loading partial data based on time or track specifications.
  856.  
  857.     Loading whole movies is OK if the movies are small, have few tracks with little info (text
  858.     tracks, music tracks and so on), there's a certain performance need  why it makes sense 
  859.     to keep the movie in RAM (looping, other issues), and in general if you know why it's needed.
  860. */
  861.  
  862. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  863. {
  864.     OSErr anErr = noErr;
  865.  
  866.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  867.  
  868.     GoToBeginningOfMovie(theMovie);
  869.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  870.     if (anErr != noErr) return anErr;
  871.  
  872.     anErr = LoadMovieIntoRam(theMovie, GetMovieTime(theMovie, NULL), GetMovieDuration(theMovie), 0);
  873.  
  874.     return anErr;
  875. }
  876.  
  877.  
  878. /*______________________________________________________________________
  879.     QTUPlayMovieSound - Play the movie sound track using the Sound Manager.
  880.  
  881. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  882.  
  883. theMovie                        movie wherefrom we extract the sound resource
  884.  
  885. DESCRIPTION
  886.     QTUPlayMovieSound is an example of how to extract the 'snd ' sound resource from the 
  887.     first sound track in a movie, and play this track back using the Sound Manager. This
  888.     sound resource could also be retrieved, or otherwised used in other instances. Note that
  889.     this function is more of an example of how to retrieve sound from a movie; you might
  890.     want to control the start point, duration, and sound track extracted.
  891.  
  892. */
  893.  
  894. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  895. {
  896.     OSErr    anErr = noErr;
  897.     Handle     tempHandle  = NewHandle(1);
  898.     
  899.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  900.  
  901.     // Extract first sound track.
  902.     anErr = PutMovieIntoTypedHandle(theMovie, (Track)0, 'snd ', tempHandle, 0, GetMovieDuration(theMovie),
  903.                                                         0, (ComponentInstance)0); DebugAssert(anErr == noErr);
  904.     if(anErr != noErr) goto Closure;
  905.     anErr = MemError(); DebugAssert(anErr == noErr);
  906.     if(anErr != noErr) goto Closure;
  907.  
  908.     // Play sound resource async.
  909.     anErr = SndPlay(0L, (SndListHandle)tempHandle, TRUE);     DebugAssert(anErr == noErr);
  910.  
  911. Closure:
  912.     if(tempHandle) DisposeHandle(tempHandle);
  913.  
  914.     return anErr;
  915. }
  916.  
  917.  
  918.  
  919. // IMAGE COMPRESSION MANAGER
  920.  
  921. /*______________________________________________________________________
  922.     QTUHasCodecLossLessQuality - Test if a specific codec has a lossless mode in a specific bit depth.
  923.  
  924. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  925.  
  926. theCodec                        specifies the Codec Type ('jpeg, 'rle ' and so on).
  927. thePixelDepth                specifies the bit depth (8, 24, 30 and so on). See NIM:QuickTime, page 
  928.                                     3-70 for more details.
  929.  
  930. DESCRIPTION
  931.     QTUHasCodecLossLessQuality will test if a specific codec has a lossless spatial compression 
  932.     quality at a certain bit depth. Note that we are not testing the temporal compression qualities.
  933.  
  934. EXAMPLE OF USE:
  935.     if(QTUHasCodecLossLessQuality('jpeg', 32))  
  936.         printf("JPEG has lossless spatial compression\n");
  937.     else
  938.         printf("JPEG has NOT lossless spatial compression\n");
  939.  
  940. */
  941.  
  942. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  943. {
  944.     OSErr     anErr = noErr;
  945.     CodecQ    aSpatialQuality = codecLosslessQuality;
  946.  
  947.     anErr = GetCompressionTime(NULL, NULL, thePixelDepth, theCodec, anyCodec, &aSpatialQuality,
  948.                         NULL, NULL); DebugAssert(anErr == noErr);
  949.     
  950.     if(aSpatialQuality == codecLosslessQuality)    // still the same?
  951.         return true;
  952.     else
  953.         return false;
  954. }
  955.  
  956.  
  957.  
  958. // MOVIE CONTROLLER FUNCTIONS
  959.  
  960.  
  961. /*______________________________________________________________________
  962.     QTUPlayMovieWithMC - Play a specific movie when using movie controllers.
  963.  
  964. pascal OSErr QTUPlayMovieWithMC( MovieController mc)
  965.  
  966. mc                        specified movie controller to be used
  967.  
  968. DESCRIPTION
  969.     Playmovie will start a movie using a moviecontroller and a specified movie. Note that it also  
  970.     does a preroll of the movie for performance reasons. 
  971.  
  972. */
  973.  
  974. pascal OSErr QTUPlayMovieWithMC(MovieController mc)
  975. {
  976. // Play normal speed forward, taking into account the possibility 
  977. // of a movie with a nonstandard PreferredRate.
  978.     OSErr    anErr = noErr;
  979.     Fixed     aRate;
  980.     Movie    aMovie;
  981.  
  982.     aMovie = MCGetMovie(mc);
  983.  
  984.     aRate= GetMoviePreferredRate(aMovie);
  985.     anErr = QTUPrerollMovie(aMovie);  // Important: Preroll the movie here.
  986.     DebugAssert(anErr == noErr);
  987.  
  988.     if(anErr == noErr)
  989.     {
  990.         MCDoAction(mc, mcActionPlay, (void *)aRate);  // note last value
  991.     }
  992.     
  993.     return anErr;
  994. }
  995.  
  996.  
  997. /*______________________________________________________________________
  998.     QTUDoIgnoreMCDrags - Disable Drag and Drop facilities of the movie controller environment.
  999.  
  1000. pascal OSErr  QTUDoIgnoreMCDrags(MovieController  mc)
  1001.  
  1002. mc                        is the specified moviecontroller to be used
  1003.  
  1004. DESCRIPTION
  1005.     QTUDoIgnoreMCDrags will ensure that the Drag and Drop functionality is not handled within 
  1006.     the movie specified by the movie controller.
  1007.  
  1008. ISSUES
  1009.     Note that this is a workaround in QT 2.0 (test for QT 2.0 or higher if you want to use
  1010.     the drag-and-drop support in QT), and this function might not be needed in later QT versions.
  1011. */
  1012.  
  1013. pascal OSErr QTUDoIgnoreMCDrags(MovieController  mc)
  1014. {
  1015.    OSErr           anErr = noErr;
  1016.    GWorldPtr  aTempGWorld;
  1017.    Rect             aTempRect = {0, 0, 20, 20};
  1018.    CGrafPtr     aPort;
  1019.  
  1020.    // First create a 1-bit small 20x20 offscreen.
  1021.    anErr = NewGWorld( &aTempGWorld, 1, &aTempRect, NULL, NULL, 0L );
  1022.    DebugAssert(anErr == noErr);
  1023.  
  1024.    if (anErr != noErr)
  1025.    {
  1026.            aPort = MCGetControllerPort(mc);                                    // get the current port
  1027.            MCSetControllerPort(mc, (CGrafPtr)aTempGWorld );        // set mc port to new offscreen
  1028.            MCDoAction(mc, mcActionSetDragEnabled, (void *)false); // don't want dragging
  1029.           MCSetControllerPort(mc, aPort);                                        // restore mc port
  1030.            DisposeGWorld(aTempGWorld);                                            // dispose offscreen
  1031.    }
  1032.    return anErr;
  1033. }
  1034.  
  1035.  
  1036. /*______________________________________________________________________
  1037.     QTUPointInMC - Test if a point is placed in the movie controller rect area or not.
  1038.  
  1039. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1040.  
  1041. mc                            is the specified moviecontroller to be used
  1042. theWindow                window used for testing for the hit point
  1043. where                        hit point
  1044.  
  1045. DESCRIPTION
  1046.     QTUPointInMC is a simple test to check where the mouse was clicked inside the window
  1047.     with a movie controller, returns true of the mouse click was inside the movie controller
  1048.     rect. See Peter Hoddie's article in develop# 18 for more details (code is from him as well).
  1049. */
  1050.  
  1051. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1052. {
  1053.     RgnHandle        aRegion;
  1054.     Boolean            result = false;
  1055.     
  1056.     aRegion = MCGetWindowRgn(mc, theWindow);
  1057.        DebugAssert(aRegion != NULL);
  1058.     
  1059.     if(aRegion != NULL)
  1060.     {
  1061.         result = PtInRgn(where, aRegion);
  1062.         DisposeRgn(aRegion);
  1063.     }
  1064.     
  1065.     return result;
  1066. }
  1067.  
  1068.  
  1069. /*______________________________________________________________________
  1070.     QTUSelectAllMovie - Select the whole movie time duration with the controller.
  1071.  
  1072. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1073.  
  1074. mc                        is the specified moviecontroller to be used
  1075.  
  1076. DESCRIPTION
  1077.     QTUSelectAllMovie is an example how to select the whole movie duration using the movie
  1078.     controller, this function could be used for Select All menu entries and similar cases.
  1079. */
  1080.  
  1081. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1082. {
  1083.     OSErr             anErr = noErr;
  1084.     TimeRecord  aTimeRecord;
  1085.     Movie             aMovie = NULL;
  1086.     
  1087.     DebugAssert(mc != NULL);
  1088.     if(mc == NULL) return paramErr;
  1089.     
  1090.     aMovie = MCGetMovie(mc); DebugAssert(aMovie != NULL);
  1091.     if(aMovie == NULL) return paramErr;
  1092.     
  1093.     aTimeRecord.value.hi = 0;
  1094.     aTimeRecord.value.lo = 0;
  1095.     aTimeRecord.base = 0;
  1096.     
  1097.     aTimeRecord.scale = GetMovieTimeScale(aMovie);
  1098.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1099.     if(anErr != noErr) return anErr;
  1100.     
  1101.     anErr = MCDoAction(mc, mcActionSetSelectionBegin, &aTimeRecord);
  1102.     DebugAssert(anErr == noErr);
  1103.     if(anErr != noErr) return anErr;
  1104.     
  1105.     aTimeRecord.value.lo = GetMovieDuration(aMovie);
  1106.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1107.     if(anErr != noErr) return anErr;
  1108.     
  1109.     anErr = MCDoAction(mc, mcActionSetSelectionDuration, &aTimeRecord);
  1110.     DebugAssert(anErr == noErr);
  1111.     
  1112.     return anErr;
  1113. }
  1114.  
  1115.  
  1116. /*______________________________________________________________________
  1117.      QTUResizeMCActionFilter - Example of a movie controller filter that will resize the window 
  1118.     where the movie is placed when the controllers themself change. 
  1119.  
  1120. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void *params, long refCon)
  1121.  
  1122. mc                            specified moviecontroller to be used.
  1123. action                        the action for the mc action filter
  1124. params                        parameters passed with the action
  1125. refCon                      additional long word that could be used for all kinds of purposes
  1126.  
  1127. DESCRIPTION
  1128.     QTUResizeMCActionFilter is an example of how to create a nice movie controller filter that 
  1129.     will handle resizing of the window with the movie, and this will happen every time the controllers
  1130.     themselves change. It's also an example of how to write other kinds of movie controller filters.
  1131. */
  1132.  
  1133. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void *params, long refCon)
  1134. {
  1135.     Rect aMovieBounds;
  1136.     
  1137.     switch(action)
  1138.     {
  1139.         case mcActionControllerSizeChanged:
  1140.             MCGetControllerBoundsRect(mc, &aMovieBounds);
  1141.             SizeWindow((WindowPtr) refCon, aMovieBounds.right - aMovieBounds.left,
  1142.                                 aMovieBounds.bottom - aMovieBounds.top, true);
  1143.             break;
  1144.     }
  1145.         return false;
  1146. }
  1147.  
  1148.  
  1149. /*______________________________________________________________________
  1150.     QTUResizeMCWindow - Resize a window to either normal size, double size or  half of the movie rect size.
  1151.  
  1152. pascal Boolean QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1153.  
  1154. mc                                specified moviecontroller to be used
  1155. theWindow                    window that will be resized
  1156. theMovieSize                constant that defines what default size we are interested in,  kNormalSize, kHalfSize, kDoubleSize
  1157. originalSize                    the original size of the movie, we need to keep track of this one in order to handle the 
  1158.                                      ambient new sizes (half, double, normal).
  1159.  
  1160. DESCRIPTION
  1161.     QTUResizeMCWindow is an example of a function how to resize the movie window with the controllers.
  1162.     The most common cases is half size, normal size or double size. But nothing hinders to add more sizes
  1163.     into this function. Note that if the movie window is doubled, we will get pixel-doubling by the QuickTime
  1164.     engine.
  1165. */
  1166.  
  1167. pascal OSErr QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1168. {
  1169.     OSErr         anErr = noErr;
  1170.     Rect             aMovieBounds;
  1171.     GrafPtr     aSavedPort;
  1172.     
  1173.     DebugAssert(mc != NULL); if(mc == NULL) return paramErr;
  1174.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1175.     
  1176.     GetPort(&aSavedPort);
  1177.     SetPort((GrafPtr)theWindow);
  1178.     
  1179.     aMovieBounds.top = 0; aMovieBounds.left = 0;
  1180.  
  1181.     switch(theMovieSize)
  1182.     {
  1183.         case kNormalMovieSize:
  1184.                 MCSetControllerBoundsRect(mc, &originalSize);
  1185.                 SizeWindow(theWindow, originalSize.right, originalSize.bottom, true);
  1186.             break;
  1187.         
  1188.         case kHalfMovieSize:
  1189.                 aMovieBounds.right = (originalSize.right - originalSize.left) / 2;
  1190.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) / 2;
  1191.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1192.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1193.             break;
  1194.         
  1195.         case kDoubleMovieSize:
  1196.                 aMovieBounds.right = (originalSize.right - originalSize.left) * 2;
  1197.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) * 2;
  1198.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1199.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1200.             break;
  1201.         
  1202.         default:
  1203.             SetPort(aSavedPort);
  1204.             anErr = paramErr;
  1205.     }
  1206.     
  1207.     SetPort(aSavedPort);
  1208.     return anErr;
  1209. }
  1210.  
  1211.  
  1212. /*______________________________________________________________________
  1213.     QTUResizeMCWindow -Change the movie rate using the movie controller. 
  1214.  
  1215. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1216.  
  1217. mc                            specified moviecontroller to be used
  1218. theRate                        new rate value, we are using specific constants, see the eQTUMovieRates enum
  1219.                                 in the DTSQTUtilities.h file concerning the values.
  1220.  
  1221. DESCRIPTION
  1222.     QTUMCSetMovieRate will use an existing movie controller and change the rate. This is a very 
  1223.     simple function, but we do have a list of constants that shows the various values that could be used 
  1224.     (eQTUMovieRates, DTSQTUtilities.h), and also it shows that if the rate changes from 0 to something 
  1225.     else, then we need to preroll the movie. The Apple MM Tuner will make sure the movie is prerolled,
  1226.     but we can't assume that every Mac has this extension installed, that's why it's still very important
  1227.     to preroll.
  1228.     
  1229. ISSUES
  1230.     Note that movies have stored preferred rates, so if you want to compensate for this factor you need
  1231.     to read in this value as well before setting a double or half speed value.
  1232. */
  1233.  
  1234. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1235. {
  1236.     OSErr     anErr = noErr;
  1237.     Fixed     aRate;
  1238.     
  1239.     DebugAssert(mc != NULL);  
  1240.     if(mc == NULL)
  1241.     {
  1242.         anErr = paramErr; goto Closure;
  1243.     }
  1244.     
  1245.     // Test if the playrate changes from 0 to a non-zero value, if so then preroll the movie.
  1246.     MCDoAction(mc, mcActionGetPlayRate, &aRate);
  1247.     if( (aRate == 0) && (theRate != 0) )
  1248.     {
  1249.         anErr = QTUPrerollMovie(MCGetMovie(mc));            // we are using the DTSQTUtilities function
  1250.         DebugAssert(anErr == noErr);
  1251.         if(anErr != noErr) return anErr;
  1252.     }
  1253.         
  1254.     anErr = MCDoAction(mc, mcActionPlay, (Ptr) theRate); DebugAssert(anErr == noErr);
  1255.  
  1256. Closure:    
  1257.     return anErr;
  1258. }
  1259.  
  1260. // SEQUENCE GRABBER FUNCTIONS
  1261. /*______________________________________________________________________
  1262.     QTUCreateSequenceGrabber - Create an instance of a sequence grabber for specified window.
  1263.  
  1264. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1265.  
  1266. theWindow                    window where the sequence grabber will operate
  1267.  
  1268. DESCRIPTION
  1269.     QTUCreateSequenceGrabber will try to open the default sequence grabber component and 
  1270.     make sure this component will work in the GWorld of a specified window. 
  1271.  
  1272.     If we don't find a suitable sequence grabber, or if we encounter problems, we will return NULL.
  1273. */
  1274.  
  1275.  
  1276. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1277. {
  1278.     OSErr anErr = noErr;
  1279.     SeqGrabComponent s = NULL;
  1280.  
  1281.     DebugAssert(theWindow != NULL); if(theWindow == NULL) goto Closure;
  1282.  
  1283.     s = OpenDefaultComponent(SeqGrabComponentType, 0);
  1284.  
  1285.     if(s) // we got a valid one
  1286.     {
  1287.         anErr = SGInitialize(s); DebugAssert(anErr == noErr);
  1288.         if(anErr != noErr) goto Closure;
  1289.  
  1290.         anErr = SGSetGWorld(s, (CGrafPtr)theWindow, NULL); DebugAssert(anErr == noErr);
  1291.         if(anErr != noErr) goto Closure;
  1292.     }
  1293.  
  1294.     return s;
  1295. Closure:
  1296.     return NULL;
  1297. }
  1298.  
  1299. /*______________________________________________________________________
  1300.     QTUCreateSGGrabChannels - Create SG channels, video and audio.
  1301.  
  1302. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1303.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1304.  
  1305. s                            current active sequence grabber component instance
  1306. theBounds                the size of the video channel sequence grabber area
  1307. theUsage                any additional flags for the video SG
  1308. theVideoChannel    pointer to the video channel we will receive
  1309. theSoundChannel    pointer to the audio channel we will receive
  1310.  
  1311.  
  1312. DESCRIPTION
  1313.     QTUCreateSGGrabChannels will create video and audio SG channels (SGChannels) using the specified
  1314.     default SG component.
  1315.  
  1316. ISSUES
  1317.     We will terminate whenever we can't properly create  a channel (sound, audio), if you still want to
  1318.     retrieve a valid channel (let's say the sound one is OK while the we can't open an audio one), you
  1319.     could slightly rewrite this code.
  1320. */
  1321.  
  1322. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1323.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1324. {
  1325.     OSErr     anErr = noErr;
  1326.     long        sgUsage = seqGrabPreview;    // default at least this flag    
  1327.  
  1328.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1329.  
  1330.     sgUsage |= theUsage;                        // add any other usage flag info now
  1331.  
  1332.     // Create Video Channel.
  1333.     anErr = SGNewChannel(s, VideoMediaType, theVideoChannel); DebugAssert(anErr == noErr);
  1334.     if(anErr != noErr) goto FailureHandling;
  1335.     
  1336.     anErr = SGSetChannelBounds(*theVideoChannel, theBounds); DebugAssert(anErr == noErr);
  1337.     if(anErr != noErr) goto FailureHandling;
  1338.  
  1339.     anErr = SGSetChannelUsage(*theVideoChannel, sgUsage); DebugAssert(anErr == noErr);
  1340.     if(anErr != noErr) goto FailureHandling;
  1341.  
  1342.     // Create Sound Channel.
  1343.     anErr = SGNewChannel(s, SoundMediaType, theSoundChannel); DebugAssert(anErr == noErr);
  1344.     if(anErr != noErr) goto FailureHandling;
  1345.  
  1346.     anErr = SGSetChannelUsage(*theSoundChannel, sgUsage); DebugAssert(anErr == noErr);
  1347.     if(anErr != noErr) goto FailureHandling;
  1348.  
  1349.  
  1350.     return anErr;
  1351.  
  1352. FailureHandling:
  1353.     SGDisposeChannel(s, *theVideoChannel); *theVideoChannel = NULL;
  1354.     SGDisposeChannel(s, *theSoundChannel); *theSoundChannel = NULL;
  1355.  
  1356.     return anErr;
  1357. }
  1358.  
  1359.  
  1360. /*______________________________________________________________________
  1361.     QTUDoesVDIGReceiveVideo - Test if vdig receives a live incoming video signal.
  1362.  
  1363. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1364.  
  1365. s                    our sequence grabber component instance
  1366.  
  1367. DESCRIPTION
  1368.     QTUDoesVDIGReceiveVideo test if the currently active vdig is receiving an incoming, live 
  1369.     video signal. We assume that all well behaved vdigs set the digiInSignalLock flag.
  1370.  
  1371. */
  1372. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1373. {
  1374.     OSErr        anErr = noErr;
  1375.     long            inputFlags, outFlags;
  1376.  
  1377.     DebugAssert(s != NULL); if(s == NULL) goto Closure;
  1378.  
  1379.     anErr = VDGetCurrentFlags(s, &inputFlags, &outFlags); DebugAssert(anErr == noErr);
  1380.     if(anErr != noErr) goto Closure;
  1381.  
  1382.     if(inputFlags & digiInSignalLock)
  1383.         return true;
  1384.  
  1385. Closure:
  1386.     return false;
  1387. }
  1388.  
  1389.  
  1390. /*______________________________________________________________________
  1391.     QTUChangeSGWindowSize - Change window size of the video sequence grabber window.
  1392.  
  1393. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, 
  1394.                             WindowPtr theWindow, long width, long height)
  1395.  
  1396. s                    our sequence grabber component instance
  1397. videoChannel    the specified (currently used) video channel
  1398. theWindow    window used for the digitizing sequence
  1399. width            new width of the digitizer rect
  1400. height            new height of the digitizer rect
  1401.  
  1402. DESCRIPTION
  1403.     QTUChangeSGWindowSize shows how to change the window size for the current digitizing sequence
  1404.     taking place in the window. This is more of an example function as there might be other issues
  1405.     to be taken into account (such as preference settings and similar issues) while changing the
  1406.     bounds of the digitizing rect.
  1407.  
  1408. */
  1409.  
  1410. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, WindowPtr theWindow, long width, long height)
  1411. {
  1412.     OSErr                                 anErr = noErr;
  1413.  
  1414.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1415.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1416.     DebugAssert(videoChannel != NULL); if(videoChannel == NULL) return badSGChannel;
  1417.  
  1418.     anErr = SGPause(s, TRUE); DebugAssert(anErr == noErr); if(anErr != noErr) goto Closure;
  1419.  
  1420.     SizeWindow(theWindow, width, height, FALSE);
  1421.     
  1422.     anErr = SGSetChannelBounds(videoChannel, &theWindow->portRect); DebugAssert(anErr == noErr);
  1423.     if(anErr != noErr) goto Closure;
  1424.  
  1425.     anErr = SGPause(s, FALSE); DebugAssert(anErr == noErr); 
  1426.  
  1427. Closure:
  1428.     return anErr;
  1429. }
  1430.  
  1431.  
  1432.  
  1433. // COMPONENT FUNCTIONS
  1434.  
  1435. /*______________________________________________________________________
  1436.     QTUDoGetComponent - Get a specific component based on component type and component sub-type.
  1437.  
  1438. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1439.  
  1440. theComponentType                    the component type we are interested in
  1441. theSpecificComponent                the specific component sub-type we are interested int
  1442.  
  1443. DESCRIPTION
  1444.     QTUDoGetComponent will get a specific component based on the component type and sub-type.  We have 
  1445.     special code for particular components (for instance movieImporttype and movieExporttype), so
  1446.     if we specify such types, the function will narrow down the search further for the right components.
  1447.     
  1448.     The specificComponent is just the special component we want to search for, if the component type is 
  1449.     NULL, then the Specific component is the one and only we are interested in. Note that we don't care 
  1450.     about the manufacturer information in this function. 
  1451.     
  1452.     If we don't find a suitable component we will return NULL.
  1453. */
  1454.  
  1455. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1456. {
  1457.     ComponentDescription     aCD;
  1458.     Component                     aComponent = NULL;
  1459.     
  1460.     aCD.componentType = theComponentType;
  1461.     aCD.componentSubType = theSpecificComponent;
  1462.     aCD.componentManufacturer = 0;
  1463.     
  1464.     // The following code is inserted for special handling of some known cases.
  1465.     if(theComponentType == MovieImportType)
  1466.     {
  1467.         aCD.componentFlags = canMovieImportFiles;
  1468.         aCD.componentFlagsMask = canMovieImportFiles;
  1469.     }
  1470.     else if(theComponentType == MovieExportType)
  1471.     {
  1472.         aCD.componentFlags = canMovieExportFiles;
  1473.         aCD.componentFlagsMask = canMovieExportFiles;
  1474.     }
  1475.  
  1476.     // OK, get the component.
  1477.     aComponent = FindNextComponent((Component)0, &aCD);
  1478.     
  1479.     return aComponent;
  1480. }
  1481.  
  1482.  
  1483. /*______________________________________________________________________
  1484.     QTUHasComponentType -Query for a specific component based on component type and 
  1485.     component sub-type.
  1486.  
  1487. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1488.  
  1489. theComponentType                    the component type we are interested in
  1490. theSpecificComponent                the specific component sub-type we are interested int
  1491.  
  1492. DESCRIPTION
  1493.     QTUDoGetComponent will query for a specific component based on the component type and sub-type.  
  1494.     We have special code for particular components (for instance movieImporttype and movieExporttype),
  1495.     so if we query for such types, the function will narrow down the search further for the right 
  1496.     components.
  1497.     
  1498.     The specificComponent is just the special component we want to search for, if the component 
  1499.     type is NULL, then the Specific component is the one and only we are interested in. Note that we 
  1500.     don't care about the manufacturer information in this function. 
  1501.     
  1502.     If we don't find a suitable component we will return false, otherwise we will return true.
  1503. */
  1504.  
  1505. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1506. {
  1507.     ComponentDescription aCD;
  1508.     
  1509.     aCD.componentType = theComponentType;
  1510.     aCD.componentSubType = theSpecificComponent;
  1511.     aCD.componentManufacturer = 0;
  1512.     
  1513.     if(theComponentType == MovieImportType)
  1514.     {
  1515.         aCD.componentFlags = canMovieImportFiles;
  1516.         aCD.componentFlagsMask = canMovieImportFiles;
  1517.     }
  1518.     else if(theComponentType == MovieExportType)
  1519.     {
  1520.         aCD.componentFlags = canMovieExportFiles;
  1521.         aCD.componentFlagsMask = canMovieExportFiles;
  1522.     }
  1523.  
  1524.     if(FindNextComponent((Component)0, &aCD) != NULL)
  1525.         return true;
  1526.     else
  1527.         return false;
  1528. }
  1529.  
  1530.  
  1531. //______________________________________________________________________
  1532. // T H E    E N D